<template>
  <div class="validate-input-container pb-3">
    <input
      class="form-control"
      :class="{ 'is-invalid': InputRef.error }"
      :value="InputRef.val"
      @blur="validateInput"
      @input="updateValue"
      v-bind="$attrs"
    >
    <span v-if="InputRef.error" class="invalid-feedback">{{InputRef.message}}</span>
  </div>
</template>

<script lang="ts">
/**
 * 父组件支持 v-model
 * 1、组件中不在使用v-model，使用:value, @input="updateValue"事件
 * 2、props接受一个modelValue
 * 3、updateValue事件中提交context.emit('update:modelValue', targetValue)
 *    ，，，targetValue是input中的值，这样就实现了一个自定义v-model
 * 4、是不是很简单呢，对比vue2呢？
*/
import { defineComponent, PropType, reactive, onMounted } from 'vue'
import { emitter } from './ValidateForm.vue'
interface RuleProp {
  type: 'required' | 'email' | 'range';
  message: string;
}
export type RulesProp = RuleProp[];
const emailReg = /^[A-Za-z\d]+([-_.][A-Za-z\d]+)*@([A-Za-z\d]+[-.])+[A-Za-z\d]{2,4}$/
export default defineComponent({
  name: 'validate-input',
  props: {
    rules: Array as PropType<RulesProp>,
    modelValue: String
  },
  inheritAttrs: false,
  setup(props, context) {
    const InputRef = reactive({
      val: props.modelValue || '',
      error: false,
      message: ''
    })
    const updateValue = (e: KeyboardEvent) => {
      const targetValue = (e.target as HTMLInputElement).value
      InputRef.val = targetValue
      context.emit('update:modelValue', targetValue)
    }
    const validateInput = () => {
      if (props.rules) {
        const allPassed = props.rules.every(rule => {
          let passed = true
          InputRef.message = rule.message
          switch (rule.type) {
            case 'required':
              passed = (InputRef.val.trim() !== '')
              break
            case 'email':
              passed = emailReg.test(InputRef.val.trim())
              break
            case 'range':
              passed = (InputRef.val.length >= 6 && InputRef.val.length <= 20)
              break
            default:
              break
          }
          return passed
        })
        InputRef.error = !allPassed
        return allPassed
      }
      return true
    }
    onMounted(() => {
      emitter.emit('form-item-created', validateInput)
    })
    return {
      InputRef,
      validateInput,
      updateValue
    }
  }
})
</script>
